package ee.reliability.tool.ui.menu;

import info.monitorenter.gui.chart.ITrace2D;
import info.monitorenter.gui.chart.axis.AxisLinear;
import info.monitorenter.gui.chart.traces.Trace2DSimple;

import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Scanner;

import javax.swing.JFileChooser;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.table.DefaultTableModel;

import org.apache.poi.ss.usermodel.Workbook;

import ee.reliability.tool.logic.Point;
import ee.reliability.tool.logic.Statistic;
import ee.reliability.tool.logic.Statistic.Element;
import ee.reliability.tool.parser.FileParser;
import ee.reliability.tool.parser.Period;
import ee.reliability.tool.parser.Period.PeriodType;
import ee.reliability.tool.ui.AxisScalePolicyFixedTicks;
import ee.reliability.tool.ui.window.ExcelFileChooser;
import ee.reliability.tool.ui.window.MainWindow;
import ee.reliability.tool.ui.window.TxtFileChooser;


@SuppressWarnings("serial")
public class MenuBar extends JMenuBar implements ActionListener{

	private final JMenuItem loadExcel;
	private final JMenuItem loadTxt;
	private final JMenuItem clear;
	private final JMenuItem work;
	private final JMenuItem sick;

	private ExcelFileChooser fileChooser;
	private TxtFileChooser txtFileChooser;
	private final List<Period> periodList;

    public MenuBar() {
    	fileChooser = new ExcelFileChooser();
    	periodList = new ArrayList<>();

        loadExcel = new JMenuItem("Load Excel");
		loadExcel.addActionListener(this);

		loadTxt = new JMenuItem("Load TXT");
		loadTxt.addActionListener(this);

		clear = new JMenuItem("Clear");
		clear.addActionListener(this);

		work = new JMenuItem("Work");
		work.addActionListener(this);

		sick = new JMenuItem("Sick");
		sick.addActionListener(this);

		JMenu file = new JMenu("File");
		JMenu view = new JMenu("View");

        file.add(loadExcel);
        file.add(loadTxt);
        file.add(clear);

        view.add(work);
        view.add(sick);

		add(file);
		add(view);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		JMenuItem initiator = (JMenuItem) e.getSource();

		if(initiator == loadExcel){
			int result = getFileChooser().showOpenDialog(getParent());
			if(result == JFileChooser.APPROVE_OPTION){
			    // Create an ITrace:

				parse(getFileChooser().getSelectedFilesAsWorkbook());
			    showGraph(PeriodType.WORKING);
			    rebuildStatisticTable(new Statistic(periodList));
            }
		}else if(initiator == loadTxt){
			int result = getTxtFileChooser().showOpenDialog(getParent());
			if(result == JFileChooser.APPROVE_OPTION){
			    // Create an ITrace:

				parseTxt(getTxtFileChooser().getSelectedFilesAsScanner());

			    showGraph(PeriodType.WORKING);
			    rebuildStatisticTable(new Statistic(periodList));
            }
		}
		else if(initiator == clear) {
			periodList.clear();
			MainWindow.getInstance().getChartPanel().getChart().removeAllTraces();
		}else if(initiator == work)
			showGraph(PeriodType.WORKING);
		else if(initiator == sick)
			showGraph(PeriodType.SICK);
	}

	private void showGraph(PeriodType periodType) {
		ITrace2D traceF = new Trace2DSimple("F");
		ITrace2D traceLineF = new Trace2DSimple("F");
		ITrace2D traceFi = new Trace2DSimple("Fi");
		traceF.setColor(Color.BLUE);
		traceLineF.setColor(Color.RED);
		traceFi.setColor(Color.GREEN);
		// Add the trace to the chart. This has to be done before adding points (deadlock prevention):
		MainWindow.getInstance().getChartPanel().getChart().removeAllTraces();
		MainWindow.getInstance().getChartPanel().getChart().addTrace(traceF);
		MainWindow.getInstance().getChartPanel().getChart().addTrace(traceLineF);
		MainWindow.getInstance().getChartPanel().getChart().addTrace(traceFi);

		LinkedList<Element> workStatistic = new Statistic(periodList).getWorkStatistic(periodType);

		rebuildTable(workStatistic);
		for(Point p : getLineTracePointsForF(workStatistic))
			traceLineF.addPoint(p.getX(),p.getY());
		for(Point p : getTracePointsForF(workStatistic))
			traceF.addPoint(p.getX(),p.getY());
		for(Point p : getTracePointsForFi(workStatistic))
			traceFi.addPoint(p.getX(),p.getY());
	}

	private void parse(ArrayList<Workbook> selectedFilesAsWorkbook) {
		for (Workbook workbook : selectedFilesAsWorkbook) {
			FileParser parser = new FileParser(workbook);
			periodList.addAll(parser.getPeriodList());
		}
	}

	private void parseTxt(ArrayList<Scanner> selectedFilesAsWorkbook) {
		for (Scanner scanner : selectedFilesAsWorkbook) {
			FileParser parser = new FileParser(scanner);
			periodList.addAll(parser.getPeriodList());
		}
	}

	private ExcelFileChooser getFileChooser() {
		if(fileChooser == null)
			fileChooser = new ExcelFileChooser();
		return fileChooser;
	}

	private TxtFileChooser getTxtFileChooser() {
		if(txtFileChooser == null)
			txtFileChooser = new TxtFileChooser();
		return txtFileChooser;
	}

	private void rebuildStatisticTable(Statistic statistic){
		DefaultTableModel dataModel = new DefaultTableModel(4, 3);
		MainWindow.getInstance().getStatisticDataTable().setModel(dataModel);
		dataModel.setValueAt("WORK", 0, 1);
		dataModel.setValueAt("SICK", 0, 2);

		dataModel.setValueAt("Average", 1, 0);
		dataModel.setValueAt(new DecimalFormat("#.###").format(statistic.getAverage(PeriodType.WORKING)), 1, 1);
		dataModel.setValueAt(new DecimalFormat("#.###").format(statistic.getAverage(PeriodType.SICK)), 1, 2);

		dataModel.setValueAt("Standart Deviation", 2, 0);
		dataModel.setValueAt(new DecimalFormat("#.###").format(statistic.getStdDeviation(PeriodType.WORKING)), 2, 1);
		dataModel.setValueAt(new DecimalFormat("#.###").format(statistic.getStdDeviation(PeriodType.SICK)), 2, 2);

		dataModel.setValueAt("Variation Coefficient", 3, 0);
		dataModel.setValueAt(new DecimalFormat("#.###").format(statistic.getVariationCoefficient(PeriodType.WORKING)), 3, 1);
		dataModel.setValueAt(new DecimalFormat("#.###").format(statistic.getVariationCoefficient(PeriodType.SICK)), 3, 2);
	}

	private void rebuildTable(LinkedList<Element> workStatistic){
		DefaultTableModel dataModel = new DefaultTableModel(5, workStatistic.size()+1);
		MainWindow.getInstance().getOutputDataTable().setModel(dataModel);
		dataModel.setValueAt("Range", 0, 0);
		dataModel.setValueAt("Mi", 1, 0);
		dataModel.setValueAt("Mti", 2, 0);
		dataModel.setValueAt("Fi", 3, 0);
		dataModel.setValueAt("F", 4, 0);
		for(int i = 0; i < workStatistic.size(); i++){
			Element element = workStatistic.get(i);
			dataModel.setValueAt(Integer.toString((int) element.getMin()) + "..." + Integer.toString((int) element.getMax()), 0, i+1);
			dataModel.setValueAt(new DecimalFormat("#.###").format(element.getMi()), 1, i+1);
			dataModel.setValueAt(new DecimalFormat("#.###").format(element.getMti()), 2, i+1);
			dataModel.setValueAt(new DecimalFormat("#.###").format(element.getFi()), 3, i+1);
			dataModel.setValueAt(new DecimalFormat("#.###").format(element.getF()), 4, i+1);
		}
	}

	private List<Point> getLineTracePointsForF(LinkedList<Element> workStatistic) {
		List<Point> pointList = new ArrayList<>();

    	for(Element element : workStatistic)
			pointList.add(new Point((int) (element.getMin() + (element.getMax() - element.getMin())/2), element.getF()));

		return pointList;
	}

    private List<Point> getTracePointsForF(LinkedList<Element> workStatistic) {
    	List<Point> pointList = new ArrayList<>();

		boolean first = true;
		((AxisScalePolicyFixedTicks)((AxisLinear)MainWindow.getInstance().getChartPanel().getChart().getAxisX()).getAxisScalePolicy()).clearPoints();
		for(int i = 0; i < workStatistic.size(); i++){
			Element element = workStatistic.get(i);
			if(first){
				((AxisScalePolicyFixedTicks)((AxisLinear)MainWindow.getInstance().getChartPanel().getChart().getAxisX()).getAxisScalePolicy()).addPoint((int) element.getMin());
				first = false;
			}
			((AxisScalePolicyFixedTicks)((AxisLinear)MainWindow.getInstance().getChartPanel().getChart().getAxisX()).getAxisScalePolicy()).addPoint((int) element.getMax());
			pointList.add(new Point((int) element.getMin(), 0));
			pointList.add(new Point((int) element.getMin(), element.getF()));
			pointList.add(new Point((int) element.getMax(), element.getF()));
			pointList.add(new Point((int) element.getMax(), 0));
		}
		return pointList;
    }

    private List<Point> getTracePointsForFi(LinkedList<Element> workStatistic) {
    	List<Point> pointList = new ArrayList<>();

    	for(Element element : workStatistic)
			pointList.add(new Point((int) (element.getMin() + (element.getMax() - element.getMin())/2), element.getFi()));
    	return pointList;
    }

}
